perm filename GRAFIX.SAI[S,HE] blob sn#558637 filedate 1981-01-23 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00018 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00003 00002	This is the stuff that does higher-level graphics, to a certain extent
C00005 00003	PROCEDURE MATX(REFERENCE REAL ARRAY A,B)
C00007 00004	PROCEDURE IDENT(REFERENCE REAL ARRAY A)
C00008 00005	PROCEDURE TRAN3(REFERENCE REAL ARRAY A REAL X,Y,Z)
C00009 00006	PROCEDURE ROT3(REFERENCE REAL ARRAY A REAL SINANG,COSANG INTEGER AXIS)
C00010 00007	PROCEDURE SCAL3(REFERENCE REAL ARRAY A REAL X,Y,Z)
C00011 00008	PROCEDURE XFORM2(REFERENCE REAL X,Y REAL ARRAY XFORM)
C00012 00009	PROCEDURE XFORM3(REFERENCE REAL X,Y,Z REAL ARRAY XFORM)
C00013 00010	INTERNAL PROCEDURE CLIP2DNORM(PROCEDURE LDRAW REAL X1,Y1,X2,Y2)
C00017 00011	PROCEDURE PDRAW(PROCEDURE LDRAW REAL X1,Y1,Z1,X2,Y2,Z2)
C00022 00012	INTERNAL PROCEDURE LINE3(PROCEDURE LDRAW REAL X1,Y1,Z1,X2,Y2,Z2)
C00025 00013	This stuff is for setting up the matrix transformations.
C00027 00014	PROCEDURE NEWVTCT
C00030 00015	PROCEDURE NEWPVP
C00032 00016	INTERNAL PROCEDURE VUPORT(REAL XPOS,YPOS,XSIZE,YSIZE)
C00033 00017	INTERNAL PROCEDURE VUWIND(REAL XAT,YAT,ZAT,XTO,YTO,ZTO,VDIST,CLPDIST)
C00034 00018	END "GRAFIX"
C00037 ENDMK
C⊗;
COMMENT This is the stuff that does higher-level graphics, to a certain extent;

ENTRY CLIP2DNORM,CLIP3DNORM,LINE3,VUPORT,VUWIND;

BEGIN "GRAFIX"

REAL ARRAY VTCT[1:4,1:4], PVP[1:4,1:4];
REAL ZNEAR,D;
REAL XE,YE,ZE,XC,YC,ZC;
REAL XW,YW,XT,YT;
PROCEDURE MATX(REFERENCE REAL ARRAY A,B);
COMMENT Multiply matrix A by B and put result in A. (Doesn't check dimensionality);
BEGIN "MATX"
REAL ARRAY TMP[ARRINFO(A,1):ARRINFO(A,2),ARRINFO(B,3):ARRINFO(B,4)];
REAL SUM;
INTEGER I,J,K;

FOR I ← ARRINFO(A,1) STEP 1 UNTIL ARRINFO(A,2) DO
    FOR J ← ARRINFO(B,3) STEP 1 UNTIL ARRINFO(B,4) DO
	BEGIN
	    SUM ← 0;
	    FOR K ← ARRINFO(B,1) STEP 1 UNTIL ARRINFO(B,2) DO
		SUM ← SUM + A[I,K]*B[K,J];
	    TMP[I,J] ← SUM
	END;
ARRTRAN(A,TMP)
END "MATX";
PROCEDURE IDENT(REFERENCE REAL ARRAY A);
COMMENT Make an identity matrix (doesn't check dimensionality);
BEGIN "IDENT"
INTEGER I,J;

FOR I ← ARRINFO(A,1) STEP 1 UNTIL ARRINFO(A,2) DO
    FOR J ← ARRINFO(A,3) STEP 1 UNTIL ARRINFO(A,4) DO
	A[I,J] ← IF I = J THEN 1.0 ELSE 0.0
END "IDENT";
PROCEDURE TRAN3(REFERENCE REAL ARRAY A; REAL X,Y,Z);
COMMENT 3-d translation;
BEGIN "TRAN3"
REAL ARRAY TRN[1:4,1:4];	COMMENT Do a real matrix translation in case the
					last column is nonzero;
IDENT(TRN);
TRN[4,1]←X; TRN[4,2]←Y; TRN[4,3]←Z;
MATX(A,TRN)
END "TRAN3";
PROCEDURE ROT3(REFERENCE REAL ARRAY A; REAL SINANG,COSANG; INTEGER AXIS);
COMMENT Do a 3-d rotation of a matrix.;
BEGIN "ROT3"
REAL ARRAY ROT[1:4,1:4];

COMMENT These formulae are on p. 335 of Newman and Sproull.;
IDENT(ROT);
CASE AXIS OF BEGIN "X Y OR Z"
["X"]	BEGIN
	ROT[2,2]←COSANG; ROT[3,3]←COSANG;
	ROT[3,2]←SINANG; ROT[2,3]←-SINANG
	END;
["Y"]	BEGIN
	ROT[1,1]←COSANG; ROT[3,3]←COSANG;
	ROT[1,3]←SINANG; ROT[3,1]←-SINANG
	END;
["Z"]	BEGIN
	ROT[1,1]←COSANG; ROT[2,2]←COSANG;
	ROT[2,1]←SINANG; ROT[1,2]←-SINANG
	END
END "X Y OR Z";
MATX(A,ROT)
END "ROT3";
PROCEDURE SCAL3(REFERENCE REAL ARRAY A; REAL X,Y,Z);
COMMENT Do a 3-d scaling of the transformation array A;
BEGIN "SCAL3"
REAL ARRAY SCL[1:4,1:4];
IDENT(SCL);
SCL[1,1]←X; SCL[2,2]←Y; SCL[3,3]←Z;
MATX(A,SCL)
END "SCAL3";
PROCEDURE XFORM2(REFERENCE REAL X,Y; REAL ARRAY XFORM);
COMMENT Do a 2-dimensional homogeneous coordinate transform;
    BEGIN "XFORM2"
	REAL XNEW,YNEW,SCALE;
	XNEW ← X*XFORM[1,1] + Y*XFORM[2,1] + XFORM[3,1];
	YNEW ← X*XFORM[1,2] + Y*XFORM[2,2] + XFORM[3,2];
	SCALE ← X*XFORM[1,3] + Y*XFORM[2,3] + XFORM[3,3];
	X ← XNEW/SCALE; Y ← YNEW/SCALE
    END "XFORM2";
PROCEDURE XFORM3(REFERENCE REAL X,Y,Z; REAL ARRAY XFORM);
COMMENT Do a 3-dimensional homogeneous coordinate transform;
    BEGIN "XFORM3"
	REAL XNEW,YNEW,ZNEW,SCALE;
	XNEW ← X*XFORM[1,1] + Y*XFORM[2,1] + Z*XFORM[3,1] + XFORM[4,1];
	YNEW ← X*XFORM[1,2] + Y*XFORM[2,2] + Z*XFORM[3,2] + XFORM[4,2];
	ZNEW ← X*XFORM[1,3] + Y*XFORM[2,3] + Z*XFORM[3,3] + XFORM[4,3];
	SCALE ← X*XFORM[1,4] + Y*XFORM[2,4] + Z*XFORM[3,4] + XFORM[4,4];
	X ← XNEW/SCALE; Y ← YNEW/SCALE; Z ← ZNEW/SCALE
    END "XFORM3";
INTERNAL PROCEDURE CLIP2DNORM(PROCEDURE LDRAW; REAL X1,Y1,X2,Y2);
COMMENT WARNING**********LDRAW procedure must have reference params.;
COMMENT This procedure clips a two-dimensional line to a square box...assuming
	that coordinates are normalized.  That is, everything is clipped to a
	box whose lower left corner is (0,0) and upper right corner is (1,1).;
COMMENT This is Cohen and Sutherland's algorithm, described in sec. 5-1 of
	Newman and Sproull's Principles of Interactive Computer Graphics, 2nd ed.;
BEGIN "CLIP2DNORM"

DEFINE  RIGHT="'2",
	LEFT="'1",
	ABOVE="'10",
	BELOW="'4",
	INSIDE="'0";

INTEGER PROCEDURE CODE(REAL X,Y);
COMMENT Returns a special code indicating the position of a point.;
BEGIN "CODE"
	INTEGER C;
	C ← INSIDE;
	IF X > 1.0 THEN C ← C LOR RIGHT ELSE IF X < 0.0 THEN C ← C LOR LEFT;
	IF Y > 1.0 THEN C ← C LOR ABOVE ELSE IF Y < 0.0 THEN C ← C LOR BELOW;
	RETURN(C)
END "CODE";

PROCEDURE HACK(REFERENCE REAL X,Y; INTEGER C);
COMMENT Clip away a protruding part of a line;
BEGIN "HACK"
COMMENT	REAL SLOPE;
COMMENT	SLOPE ← (Y2-Y1)/(X2-X1);
COMMENT Don't try to optimize common subexpressions...blows up on divide by zero.;
	IF (C LAND LEFT) THEN
	    BEGIN
		Y ← Y1 - ((Y2-Y1)/(X2-X1))*X1;
		X ← 0.0
	    END
	ELSE IF (C LAND RIGHT) THEN
	    BEGIN
		Y ← Y1 + ((Y2-Y1)/(X2-X1))*(1.0-X1);
		X ← 1.0
	    END;
	IF (C LAND BELOW) THEN
	    BEGIN
		X ← X1 - ((X2-X1)/(Y2-Y1))*Y1;
		Y ← 0.0
	    END
	ELSE IF (C LAND ABOVE) THEN
	    BEGIN
		X ← X1 + ((X2-X1)/(Y2-Y1))*(1.0-Y1);
		Y ← 1.0
	    END
END "HACK";

INTEGER C1,C2;
C1 ← CODE(X1,Y1);  C2 ← CODE(X2,Y2);
WHILE (C1 LOR C2) ≠ INSIDE DO
    BEGIN "CLIP AWAY"
	IF (C1 LAND C2) ≠ INSIDE THEN RETURN;	COMMENT Trivially invisible;
	IF C1 ≠ INSIDE THEN HACK(X1,Y1,C1);
	IF C2 ≠ INSIDE THEN HACK(X2,Y2,C2);
	C1 ← CODE(X1,Y1);  C2 ← CODE(X2,Y2)
    END "CLIP AWAY";
LDRAW(X1,Y1,X2,Y2)
END "CLIP2DNORM";
PROCEDURE PDRAW(PROCEDURE LDRAW; REAL X1,Y1,Z1,X2,Y2,Z2);
COMMENT Reference parameters because of the way SAIL works (see CLIP3DNORM);
COMMENT Make the perspective transformation, then the viewport transformation
	and the final clipping.;
BEGIN "PDRAW"
XFORM3(X1,Y1,Z1,PVP);
XFORM3(X2,Y2,Z2,PVP);
CLIP2DNORM(LDRAW,X1,Y1,X2,Y2)
END "PDRAW";

INTERNAL PROCEDURE CLIP3DNORM(PROCEDURE LDRAW; REAL X1,Y1,Z1,X2,Y2,Z2,ZNEAR);
COMMENT WARNING**********DRAW procedure must have reference params.;
COMMENT This procedure clips a three-dimensional line to a view pyramid...assuming
	that coordinates are normalized.  That is, everything is clipped to a
	pyramid bounded by the planes x=z, x=-z, y=z, y=-z, and z=ZNEAR.;
COMMENT This is Cohen and Sutherland's algorithm, described in sec. 22-6 of
	Newman and Sproull's Principles of Interactive Computer Graphics, 2nd ed.;
BEGIN "CLIP3DNORM"

DEFINE  RIGHT="'2",
	LEFT="'1",
	ABOVE="'10",
	BELOW="'4",
	INSIDE="'0",
	FRONT="'20";

INTEGER PROCEDURE CODE(REAL X,Y,Z);
COMMENT Returns a special code indicating the position of a point.;
BEGIN "CODE"
	INTEGER C;
	C ← INSIDE;
	IF X > Z THEN C ← C LOR RIGHT ELSE IF X < -Z THEN C ← C LOR LEFT;
	IF Y > Z THEN C ← C LOR ABOVE ELSE IF Y < -Z THEN C ← C LOR BELOW;
	IF Z < ZNEAR THEN C ← C LOR FRONT;
	RETURN(C)
END "CODE";

PROCEDURE HACK(REFERENCE REAL X,Y,Z; INTEGER C);
COMMENT Clip away a protruding part of a line;
BEGIN "HACK"
	REAL T;

	COMMENT This code is easier to understand if you know that the line is
		being represented parametrically as
			x = T*(X2-X1) + X1
			y = T*(Y2-Y1) + Y1
			z = T*(Z2-Z1) + Z1
		where T varies from 0 at point 1 to 1 at point 2.;
	comment the formulae were all copied from the book, one of them was verified
		using macsyma.  The z-clipping formula is not in the book and was
		derived by hand;

	IF (C LAND LEFT) THEN
	    BEGIN
		T ← (Z1+X1)/((X1-X2)-(Z2-Z1));
		Z ← T*(Z2-Z1) + Z1;
		X ← -Z;
		Y ← T*(Y2-Y1) + Y1
	    END
	ELSE IF (C LAND RIGHT) THEN
	    BEGIN
		T ← (Z1-X1)/((X2-X1)-(Z2-Z1));
		Z ← T*(Z2-Z1) + Z1;
		X ← Z;
		Y ← T*(Y2-Y1) + Y1
	    END;
	IF (C LAND BELOW) THEN
	    BEGIN
		T ← (Z1+Y1)/((Y1-Y2)-(Z2-Z1));
		Z ← T*(Z2-Z1) + Z1;
		X ← T*(X2-X1) + X1;
		Y ← -Z
	    END
	ELSE IF (C LAND ABOVE) THEN
	    BEGIN
		T ← (Z1-Y1)/((Y2-Y1)-(Z2-Z1));
		Z ← T*(Z2-Z1) + Z1;
		X ← T*(X2-X1) + X1;
		Y ← Z
	    END;
	IF (C LAND FRONT) THEN
	    BEGIN
		T ← (ZNEAR-Z1)/(Z2-Z1);
		X ← T*(X2-X1) + X1;
		Y ← T*(Y2-Y1) + Y1;
		Z ← ZNEAR
	    END
END "HACK";

INTEGER C1,C2;
C1 ← CODE(X1,Y1,Z1);  C2 ← CODE(X2,Y2,Z2);
WHILE (C1 LOR C2) ≠ INSIDE DO
    BEGIN "CLIP AWAY"
	IF (C1 LAND C2) ≠ INSIDE THEN RETURN;	COMMENT Trivially invisible;
	IF C1 ≠ INSIDE THEN HACK(X1,Y1,Z1,C1);
	IF C2 ≠ INSIDE THEN HACK(X2,Y2,Z2,C2);
	C1 ← CODE(X1,Y1,Z1);  C2 ← CODE(X2,Y2,Z2)
    END "CLIP AWAY";
PDRAW(LDRAW,X1,Y1,Z1,X2,Y2,Z2)
END "CLIP3DNORM";
INTERNAL PROCEDURE LINE3(PROCEDURE LDRAW; REAL X1,Y1,Z1,X2,Y2,Z2);
COMMENT Draw a line in 3-d.;
BEGIN "LINE3"
COMMENT Transform the points to viewing space, then to clipping space, then
	clip them against the viewing pyramid, then take the perspective
	transformation, then the viewport transformation and finally the
	screen clipping!;
XFORM3(X1,Y1,Z1,VTCT);
XFORM3(X2,Y2,Z2,VTCT);
CLIP3DNORM(LDRAW,X1,Y1,Z1,X2,Y2,Z2,ZNEAR)

END "LINE3";
COMMENT This stuff is for setting up the matrix transformations.;

PROCEDURE NEWVTCT;
COMMENT Make a new view transform/clip transform matrix.;
BEGIN "NEWVTCT"
REAL ARRAY CLP[1:4,1:4];
REAL DX,DY,DZ,DXY,DXY2,DXYZ;
INTEGER I;
IDENT(VTCT);
TRAN3(VTCT,-XE,-YE,-ZE);	COMMENT Move us to (Xe,Ye,Ze) by moving the world
					in the other direction.;
COMMENT Find description of rotations needed.;
DX ← XE-XC; DY ← YE-YC; DZ ← ZE-ZC;
DXY2 ← DX*DX+DY*DY; DXY ← SQRT(DXY2);
DXYZ ← SQRT(DXY2+DZ*DZ);

COMMENT Bring the x axis into place.;
ROT3(VTCT,DX/DXY,-DY/DXY,"Z");

COMMENT And now the y and z axes.;
ROT3(VTCT,-DZ/DXYZ,DXY/DXYZ,"X");

COMMENT Then change to the left-handed viewing coordinate system.;
FOR I ← 1 STEP 1 UNTIL 4 DO VTCT[I,2] ↔ VTCT[I,3];

COMMENT Now add on the pre-clipping transformation.;
IDENT(CLP);
CLP[1,1] ← 2*D;
CLP[2,2] ← 2*D;
MATX(VTCT,CLP)

END "NEWVTCT";
PROCEDURE NEWPVP;
COMMENT Make a new perspective and viewport transformation.;
BEGIN "NEWPVP"

COMMENT Now do the perspective transformation.;
IDENT(PVP);
PVP[3,3] ← 0; PVP[3,4] ← 2;	COMMENT 2 fixes up window size;
PVP[4,3] ← -1.0; PVP[4,4] ← 0.0;COMMENT -1 keeps z's in order;

COMMENT Move to a 0-1 coordinate space.;
TRAN3(PVP,0.5,0.5,0.0);

COMMENT Do the scaling for the viewport transformation.;
SCAL3(PVP,XW,YW,1.0);

COMMENT And finally, position the viewport.;
TRAN3(PVP,XT,YT,0.0)

END "NEWPVP";
INTERNAL PROCEDURE VUPORT(REAL XPOS,YPOS,XSIZE,YSIZE);
BEGIN
XW ← XSIZE; YW ← YSIZE; XT ← XPOS; YT ← YPOS;
NEWPVP
END;
INTERNAL PROCEDURE VUWIND(REAL XAT,YAT,ZAT,XTO,YTO,ZTO,VDIST,CLPDIST);
BEGIN
XE ← XAT; YE ← YAT; ZE ← ZAT;
XC ← XTO; YC ← YTO; ZC ← ZTO;
D ← VDIST;
ZNEAR ← CLPDIST;
NEWVTCT
END;

END "GRAFIX"